using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using LitJson;

/// <summary>
/// <para>教学系统节点的虚基类，无事件触发的教学节点继承该类</para>
/// </summary>
[JsonClassAttribute]
public abstract class TutorialNode
{
	/// <summary>
	/// <para>当前的教学管理器，可使用其MonoBehavior来StartCoroutine</para>
	/// </summary>
	protected TutorialManager _tutorialManager;

	/// <summary>
	/// <para>延时初始化的时长，暂时未开放使用</para>
	/// </summary>
	//[JsonAttribute("delay", "延迟")]
	public float _delay = 0f;

	/// <summary>
	/// <para>是否已经初始化，配合延时参数使用</para>
	/// </summary>
	bool _hasInit = false;

	/// <summary>
	/// <para>延时启动的协程，配合延时参数使用</para>
	/// </summary>
	Coroutine _startCoroutine = null;

	/// <summary>
	/// <para>启动节点，如果设置了延时参数，则启动延时协程</para>
	/// </summary>
	public void Start(TutorialManager manager)
	{
		_tutorialManager = manager;
		_startCoroutine = _tutorialManager.StartCoroutine(Start());
	}

	/// <summary>
	/// <para>延时协程函数</para>
	/// </summary>
	IEnumerator Start()
	{
		if (_delay > 0) {
			yield return new WaitForSeconds(_delay);
		}
        OnEnter();
        _hasInit = true;
	}

    /// <summary>
    /// 扩展组件列表
    /// </summary>
    protected List<TutorialComponent> componentList =new List<TutorialComponent>();

	/// <summary>
	/// <para>退出该节点</para>
	/// </summary>
	public void Stop()
	{
		if (_hasInit)
            OnExit();
		else {
			if (_startCoroutine != null) {
				_tutorialManager.StopCoroutine(_startCoroutine);
				_startCoroutine = null;
			}
		}
	}

    private void OnEnter()
    {
        Init();
        OnCompontListEnter();
    }

    private void OnExit()
    {
        Cancel();
        OnCompontListExit();
    }

	/// <summary>
	/// <para>初始化虚函数，供子类继承</para>
	/// </summary>
	protected abstract void Init();

	/// <summary>
	/// <para>退出虚函数，供子类继承</para>
	/// </summary>
	protected abstract void Cancel();

    protected virtual void OnCompontListEnter()
    {
        for (int i = 0; i < componentList.Count; i++)
        {
            componentList[i].OnEnter();
        }
    }

    protected virtual void OnCompontListExit()
    {
        for (int i = 0; i < componentList.Count; i++)
        {
            componentList[i].OnExit();
        }
    }

    protected void AddTutorialComponent(TutorialComponent component)
    {
        componentList.Add(component);
    }
}

/// <summary>
/// <para>教学系统带有事件触发的节点的虚基类，有事件触发的教学节点继承该类</para>
/// </summary>
public abstract class TutorialEventNode : TutorialNode
{
	/// <summary>
	/// <para>事件触发后所跳转的步骤的标签</para>
	/// </summary>
	public string _nextTag = "";

    /// <summary>
    /// 节点工作方式定义
    /// </summary>
    public enum WorkType {
        /// <summary>
        /// 串行
        /// </summary>
        Serial,
        /// <summary>
        /// 并行
        /// </summary>
        parallel,
    }

	/// <summary>
	/// <para>可跳转的标签列表</para>
	/// </summary>
	[JsonAttribute("nTag", "跳转标签", "", "func: GetTagLabels")]
	public List<string> _switchTags = new List<string>(){ "" };

#if UNITY_EDITOR
#pragma warning disable 0414
    [JsonEditorAttribute(typeof(SwitchTagsJsonSpecialMember), "nTag")]
	public List<int> _switchTagsIndex = new List<int>();
#pragma warning restore
#endif

    /// <summary>
	/// <para>可跳转的标签列表的文本获取函数，在JsonAttribute的参数中通过反射获取</para>
    /// </summary>
    public virtual string[] GetTagLabels()
	{
		return new string[]{ "跳转标签" };
	}

	/// <summary>
	/// <para>事件触发时的回调函数</para>
	/// </summary>
	protected Action<TutorialEventNode> _shootEvent;

	/// <summary>
	/// <para>开始这个节点</para>
	/// </summary>
	public void Start(TutorialManager manager, Action<TutorialEventNode> shootEvent)
	{
		Start(manager);
		_shootEvent = shootEvent;
	}

	/// <summary>
	/// <para>触发事件并跳转到第一个标签所对应的步骤</para>
	/// </summary>
	public void Shoot()
	{
		Shoot(0);
	}

	/// <summary>
	/// <para>触发事件并跳转到序号为tagIndex的标签所对应的步骤</para>
	/// </summary>
	public void Shoot(int tagIndex)
	{
		if (_switchTags.Count > tagIndex)
			_nextTag = _switchTags[tagIndex];
		if (_shootEvent != null) {
            OnShoot();
            _shootEvent(this);
			_shootEvent = null;
		}
	}

    /// <summary>
    /// 触发事件
    /// </summary>
    protected virtual void OnShoot()
    {

    }
}

/// <summary>
/// <para>教学步骤</para>
/// </summary>
public class TutorialStep
{
	/// <summary>
	/// <para>步骤标签</para>
	/// </summary>
	[JsonAttribute("tag")]
	public string _tag;

    /// <summary>
    /// <para>该步骤所包含的子节点列表</para>
    /// </summary>
    [JsonAttribute("nodes")]
	public List<TutorialNode> _nodes = new List<TutorialNode>() { };

	/// <summary>
	/// <para>事件触发后的回调函数</para>
	/// </summary>
	Action<string> _shootEvent = null;

    bool resumeUIEvent = false;

	/// <summary>
	/// <para>初始化函数，启动该步骤所有子节点</para>
	/// </summary>
	public void Init(TutorialManager manager, Action<string> shootEvent)
	{
        //CloseAllEventSystem();
        for (int i = 0; i < _nodes.Count; ++i) {
			if (_nodes[i] is TutorialEventNode)
				((TutorialEventNode)_nodes[i]).Start(manager, ShootEventsCallback);
			else 
				_nodes[i].Start(manager);
		}
        //manager.StartCoroutine(OpenALlEventSystem());
        _shootEvent = shootEvent;
	}

    public void CloseAllEventSystem()
    {
        InputUtils.TutorialDisable();
        if (UIUtils.GetUIEventSystemState())
        {
            resumeUIEvent = true;
            UIUtils.CloseUIEventSystem();
        }
    }

    public IEnumerator OpenALlEventSystem()
    {
        yield return new WaitForEndOfFrame();
        InputUtils.TutorialEnable();
        if (resumeUIEvent)
        {
            UIUtils.OpenUIEventSystem();
        }
    }

	/// <summary>
	/// <para>传递给子事件节点的回调函数</para>
	/// </summary>
	void ShootEventsCallback(TutorialEventNode node)
	{
        if(node._nextTag == TutorialManager.emptyTag)
        {
            node.Stop();
            _nodes.Remove(node);
            return;
        }
		Clear();

		int idx = _nodes.IndexOf(node);
		if (idx >= 0) {
			if (_shootEvent != null) {
				_shootEvent(node._nextTag);
				if (node._nextTag != _tag)
					_shootEvent = null;
			}
		}
	}

	/// <summary>
	/// <para>停止所有的子节点</para>
	/// </summary>
	public void Clear()
	{
		for (int i = 0; i < _nodes.Count; ++i) {
			_nodes[i].Stop();
		}
	}
}

/// <summary>
/// <para>教学脚本类，一个教学脚本包含一系列教学步骤和一系列公用节点</para>
/// </summary>
public class TutorialScript
{
	/// <summary>
	/// <para>初始步骤的标签</para>
	/// </summary>
	[JsonAttribute("sTag")]
	public string _startTag = "";

	/// <summary>
	/// <para>所有步骤列表</para>
	/// </summary>
	[JsonAttribute("step")]
	public List<TutorialStep> _steps = new List<TutorialStep>();

	/// <summary>
	/// <para>所有公用节点的列表</para>
	/// </summary>
	[JsonAttribute("nodes")]
	public List<TutorialNode> _nodes = new List<TutorialNode>();

	/// <summary>
	/// <para>当前的教学管理器，可使用其MonoBehavior来StartCoroutine</para>
	/// </summary>
	TutorialManager _tutorialManager;

	/// <summary>
	/// <para>当前正在执行的教学步骤</para>
	/// </summary>
	TutorialStep _currentStep = null;

	/// <summary>
	/// <para>事件触发时的回调函数</para>
	/// </summary>
	Action<string> _shootEvent = null;

	/// <summary>
	/// <para>启动该教学脚本</para>
	/// </summary>
	public bool Start(TutorialManager manager, string startTag = "")
	{
	

		if (_steps.Count == 0) {
			Debug.LogWarning("Warning! Not any step in script");
			return false;
		}

		_tutorialManager = manager;
        if (string.IsNullOrEmpty(startTag))
			startTag = _startTag;
		if (!PerformStep(startTag))
			PerformStep(_steps[0]._tag);

		return true;
	}

    /// <summary>
    /// 执行公共节点
    /// </summary>
    void StartCommonNodes()
    {
        for (int i = 0; i < _nodes.Count; ++i)
        {
            if (_nodes[i] is TutorialEventNode)
                ((TutorialEventNode)_nodes[i]).Start(_tutorialManager, ShootEventsCallback);
            else
                _nodes[i].Start(_tutorialManager);
        }
    }

	/// <summary>
	/// <para>事件触发时的回调函数</para>
	/// </summary>
	void ShootEventsCallback(TutorialEventNode node)
	{

		Clear();

		int idx = _nodes.IndexOf(node);
		if (idx >= 0) {
			if (_shootEvent != null) {
				_shootEvent(node._nextTag);
				if (node._nextTag != _startTag)
					_shootEvent = null;
			}
		}
	}

	/// <summary>
	/// <para>停止所有的公用节点</para>
	/// </summary>
	public void Clear()
	{
		for (int i = 0; i < _nodes.Count; ++i) {
			_nodes[i].Stop();
		}
	}

	/// <summary>
	/// <para>根据标签获取教学步骤</para>
	/// </summary>
	TutorialStep GetStep(string tag)
	{
		for (int i = 0; i < _steps.Count; ++i) {
			if (_steps[i]._tag == tag) {
				return _steps[i];
			}
		}

		return null;
	}

	/// <summary>
	/// <para>判断是否存在某个标签的教学步骤</para>
	/// </summary>
	public bool HasStep(string tag)
	{
		return GetStep(tag) != null;
	}

    /// <summary>
    /// 获取所有的步骤的Tag
    /// </summary>
    /// <returns></returns>
    public List<string> GetAllStepTags()
    {
        List<string> retList = new List<string>();
        for (int i = 0; i < _steps.Count; ++i)
        {
            retList.Add(_steps[i]._tag);
        }

        return retList;
    }

	/// <summary>
	/// <para>根据标签启动对应的教学步骤</para>
	/// </summary>
	bool PerformStep(string tag)
	{
		var step = GetStep(tag);
		if (step != null) {
			_currentStep = step;
            StartCommonNodes();
            step.Init(_tutorialManager, CheckPerformStep);
			return true;
		} else
			return false;
	}

	/// <summary>
	/// <para>根据标签启动对应的教学步骤，并根据其返回结果判断是否要结束整个教学脚本</para>
	/// </summary>
	void CheckPerformStep(string tag)
	{
        if (tag == TutorialManager.endstag)
        {
            End();
        }
        PerformStep(tag);

    }

	/// <summary>
	/// <para>强制停止当前步骤并结束教学脚本</para>
	/// </summary>
	public void Stop()
	{
		if (_currentStep != null) {
			_currentStep.Clear();
		}
	}

	/// <summary>
	/// <para>教学脚本正常结束</para>
	/// </summary>
	void End()
	{
		_tutorialManager.Ends();
	}

	/// <summary>
	/// <para>教学脚本的脚本名</para>
	/// </summary>
	public string Name { set; get; }

	/// <summary>
	/// <para>从Json数据中反序列化为TutorialScript对象</para>
	/// </summary>
	public static TutorialScript LoadFromJson(string json)
	{
		object script = null;
		JsonData data = JsonMapper.ToObject(json);
		TutorialJsonUtils.ReadFromJson(ref script, typeof(TutorialScript), data);
		return script == null ? new TutorialScript() : (TutorialScript)script;
	}

	#if UNITY_EDITOR
	/// <summary>
	/// <para>将当期教学脚本序列化为json数据</para>
	/// </summary>
	public string SaveAsJson()
	{
		return FormatJsonString(((JsonData)TutorialJsonUtils.GetJsonData(this)).ToJson());
	}

	private string FormatJsonString(string str)
	{
		//格式化json字符串
		Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
		System.IO.TextReader tr = new System.IO.StringReader(str);
		Newtonsoft.Json.JsonTextReader jtr = new Newtonsoft.Json.JsonTextReader(tr);
		object obj = serializer.Deserialize(jtr);
		if (obj != null)
		{
			System.IO.StringWriter textWriter = new System.IO.StringWriter();
			Newtonsoft.Json.JsonTextWriter jsonWriter = new Newtonsoft.Json.JsonTextWriter(textWriter)
			{
				Formatting = Newtonsoft.Json.Formatting.Indented,
				Indentation = 2,
				IndentChar = ' '
			};
			serializer.Serialize(jsonWriter, obj);
			return textWriter.ToString();
		}
		else
		{
			return str;
		}         
	}
	#endif
}


